package com.qsw.radioview.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;

@SuppressLint("AppCompatCustomView")
public class RadioViewButton extends RadioButton {
    private static final String TAG = "TAG_RadioViewButton";

    private static final byte SHAPE_TYPE_ONLY_ONE = 1;// 仅一个RadioButton
    private static final byte SHAPE_TYPE_LEFT = 2;// 两个及两个以上RadioButton的最左侧
    private static final byte SHAPE_TYPE_CENTER = 3;// 两个及两个以上RadioButton的中间
    private static final byte SHAPE_TYPE_RIGHT = 4;// 两个及两个以上RadioButton的最右侧

    private int mDrawInterval;// 绘制背景时的四周间隔，防止太靠近边缘出现断点，单位：px
    private int mCheckedStrokeColor = Color.parseColor("#ff4040");// 选中时边框颜色
    private int mNoCheckedStrokeColor = Color.parseColor("#535353");// 未选中时边框颜色
    private int mCheckedFillColor = Color.parseColor("#ff4040");// 选中时填充颜色
    private int mNoCheckedFillColor = Color.parseColor("#535353");// 未选中时填充颜色
    private int mCheckedTextColor = Color.parseColor("#ff4040");// 选中时文字颜色
    private int mNoCheckedTextColor = Color.parseColor("#535353");// 未选中时文字颜色

    private int mStrokeLineWidth = 1;// 边框线宽，单位：dp

    private Paint mPaint;

    private byte mShapeType = Byte.MIN_VALUE;
    private int mLeftRbIndexOfAll;// 左侧RadioButuon索引，包含父布局中的所有子View
    private int mRightRbIndexOfAll;// 右侧RadioButuon索引，包含父布局中的所有子View

    private boolean mDrawStroke = true;// 是否绘制边框
    private boolean mDrawFill = false; // 是否绘制中部填充

    public RadioViewButton(Context context) {
        super(context);
        init();
    }

    public RadioViewButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RadioViewButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setButtonDrawable(null);
        mDrawInterval = dp2px(getContext(), mStrokeLineWidth) / 2;
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(dp2px(getContext(), mStrokeLineWidth));
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mShapeType = Byte.MIN_VALUE;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mShapeType <= 0) {
            if (!(getParent() instanceof ViewGroup)) {
                return;
            }
            ViewGroup parent = (ViewGroup) getParent();
            mLeftRbIndexOfAll = -1;
            mRightRbIndexOfAll = -1;
            int lastRbIndexOfAll = -1;
            int indexOfVisible = -1;
            int visibleCount = 0;
            int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View view = parent.getChildAt(i);
                if (view.equals(this)) {
                    indexOfVisible = visibleCount;
                    mLeftRbIndexOfAll = lastRbIndexOfAll;
                } else if (view instanceof RadioButton) {
                    if (indexOfVisible >= 0 && mRightRbIndexOfAll < 0) {
                        mRightRbIndexOfAll = i;
                    }
                    lastRbIndexOfAll = i;
                }
                if (view.getVisibility() == View.VISIBLE) {
                    visibleCount++;
                }
            }
            if (indexOfVisible < 0) {
                return;
            }
            if (visibleCount == 1) {
                mShapeType = SHAPE_TYPE_ONLY_ONE;
            } else if (indexOfVisible == 0) {
                mShapeType = SHAPE_TYPE_LEFT;
            } else if (indexOfVisible == visibleCount - 1) {
                mShapeType = SHAPE_TYPE_RIGHT;
            } else {
                mShapeType = SHAPE_TYPE_CENTER;
            }
        }

        switch (mShapeType) {
            case SHAPE_TYPE_ONLY_ONE:
                drawOnlyOneShape(canvas);
                break;
            case SHAPE_TYPE_LEFT:
                drawLeftShape(canvas);
                break;
            case SHAPE_TYPE_CENTER:
                drawCenterShape(canvas);
                break;
            case SHAPE_TYPE_RIGHT:
                drawRightShape(canvas);
                break;
        }

        setTextColor(isChecked() ? mCheckedTextColor : mNoCheckedTextColor);
        super.onDraw(canvas);
    }

    /**
     * 当只有一个时绘制
     *
     * @param canvas 画板
     */
    private void drawOnlyOneShape(Canvas canvas) {
        if (mDrawFill) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(isChecked() ? mCheckedFillColor : mNoCheckedFillColor);
            Path path = new Path();
            path.moveTo(getHeight() / 2, mDrawInterval);
            path.lineTo(getWidth() - getHeight() / 2, mDrawInterval);
            path.arcTo(getWidth() - getHeight() + mDrawInterval, mDrawInterval, getWidth() - mDrawInterval, getHeight() - mDrawInterval, -90, 180, false);
            path.lineTo(getHeight() / 2, getHeight() - mDrawInterval);
            path.arcTo(mDrawInterval, mDrawInterval, getHeight() - mDrawInterval, getHeight() - mDrawInterval, 90, 180, false);
            canvas.drawPath(path, mPaint);
        }
        if (mDrawStroke) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(isChecked() ? mCheckedStrokeColor : mNoCheckedStrokeColor);
            canvas.drawArc(mDrawInterval, mDrawInterval, getHeight() - mDrawInterval, getHeight() - mDrawInterval, 90, 180, false, mPaint);
            canvas.drawLine(getHeight() / 2, mDrawInterval, getWidth() - getHeight() / 2, mDrawInterval, mPaint);
            canvas.drawLine(getHeight() / 2, getHeight() - mDrawInterval, getWidth() - getHeight() / 2, getHeight() - mDrawInterval, mPaint);
            canvas.drawArc(getWidth() - getHeight() + mDrawInterval, mDrawInterval, getWidth() - mDrawInterval, getHeight() - mDrawInterval, -90, 180, false, mPaint);
        }
    }

    /**
     * 当在左侧时绘制
     *
     * @param canvas 画板
     */
    private void drawLeftShape(Canvas canvas) {
        if (mDrawFill) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(isChecked() ? mCheckedFillColor : mNoCheckedFillColor);
            Path path = new Path();
            path.moveTo(getHeight() / 2, mDrawInterval);
            path.lineTo(getWidth(), mDrawInterval);
            path.lineTo(getWidth(), getHeight() - mDrawInterval);
            path.lineTo(getHeight() / 2, getHeight() - mDrawInterval);
            path.arcTo(mDrawInterval, mDrawInterval, getHeight() - mDrawInterval, getHeight() - mDrawInterval, 90, 180, false);
            canvas.drawPath(path, mPaint);
        }
        if (mDrawStroke) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(isChecked() ? mCheckedStrokeColor : mNoCheckedStrokeColor);
            // 绘制左侧弧形和上下边线
            canvas.drawArc(mDrawInterval, mDrawInterval, getHeight() - mDrawInterval, getHeight() - mDrawInterval, 90, 180, false, mPaint);
            canvas.drawLine(getHeight() / 2, mDrawInterval, getWidth(), mDrawInterval, mPaint);
            canvas.drawLine(getHeight() / 2, getHeight() - mDrawInterval, getWidth(), getHeight() - mDrawInterval, mPaint);
            // 绘制右侧竖线
            if (isChecked()
                    || mRightRbIndexOfAll < 0
                    || !((RadioButton) ((ViewGroup) getParent()).getChildAt(mRightRbIndexOfAll)).isChecked()) {
                canvas.drawLine(getWidth() - mDrawInterval, mDrawInterval, getWidth() - mDrawInterval, getHeight() - mDrawInterval, mPaint);
            }
        }
    }

    /**
     * 当在中间时绘制
     *
     * @param canvas 画板
     */
    private void drawCenterShape(Canvas canvas) {
        if (mDrawFill) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(isChecked() ? mCheckedFillColor : mNoCheckedFillColor);
            Path path = new Path();
            path.moveTo(0, mDrawInterval);
            path.lineTo(getWidth(), mDrawInterval);
            path.lineTo(getWidth(), getHeight() - mDrawInterval);
            path.lineTo(0, getHeight() - mDrawInterval);
            path.close();
            canvas.drawPath(path, mPaint);
        }
        if (mDrawStroke) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(isChecked() ? mCheckedStrokeColor : mNoCheckedStrokeColor);
            // 绘制上下边线
            canvas.drawLine(0, mDrawInterval, getWidth(), mDrawInterval, mPaint);
            canvas.drawLine(0, getHeight() - mDrawInterval, getWidth(), getHeight() - mDrawInterval, mPaint);
            // 绘制左侧竖线
            if (isChecked()
                    || mLeftRbIndexOfAll < 0) {
                canvas.drawLine(mDrawInterval, mDrawInterval, mDrawInterval, getHeight() - mDrawInterval, mPaint);
            }
            // 绘制右侧竖线
            if (isChecked()
                    || mRightRbIndexOfAll < 0
                    || !((RadioButton) ((ViewGroup) getParent()).getChildAt(mRightRbIndexOfAll)).isChecked()) {
                canvas.drawLine(getWidth() - mDrawInterval, mDrawInterval, getWidth() - mDrawInterval, getHeight() - mDrawInterval, mPaint);
            }
        }
    }

    /**
     * 当在右侧时绘制
     *
     * @param canvas 画板
     */
    private void drawRightShape(Canvas canvas) {
        if (mDrawFill) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(isChecked() ? mCheckedFillColor : mNoCheckedFillColor);
            Path path = new Path();
            path.moveTo(0, mDrawInterval);
            path.lineTo(getWidth() - getHeight() / 2, mDrawInterval);
            path.arcTo(getWidth() - getHeight() + mDrawInterval, mDrawInterval, getWidth() - mDrawInterval, getHeight() - mDrawInterval, -90, 180, false);
            path.lineTo(0, getHeight() - mDrawInterval);
            path.close();
            canvas.drawPath(path, mPaint);
        }
        if (mDrawStroke) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(isChecked() ? mCheckedStrokeColor : mNoCheckedStrokeColor);
            // 绘制右侧弧形和上下边线
            canvas.drawArc(getWidth() - getHeight() + mDrawInterval, mDrawInterval, getWidth() - mDrawInterval, getHeight() - mDrawInterval, -90, 180, false, mPaint);
            canvas.drawLine(0, mDrawInterval, getWidth() - getHeight() / 2, mDrawInterval, mPaint);
            canvas.drawLine(0, getHeight() - mDrawInterval, getWidth() - getHeight() / 2, getHeight() - mDrawInterval, mPaint);
            // 绘制左侧竖线
            if (isChecked()
                    || mLeftRbIndexOfAll < 0) {
                canvas.drawLine(mDrawInterval, mDrawInterval, mDrawInterval, getHeight() - mDrawInterval, mPaint);
            }
        }
    }

    /**
     * 是否绘制边框
     *
     * @return 是否绘制边框
     */
    public boolean isDrawStroke() {
        return mDrawStroke;
    }

    /**
     * 是否绘制填充
     *
     * @return 是否绘制填充
     */
    public boolean isDrawFill() {
        return mDrawFill;
    }

    /**
     * 设置绘制类型
     *
     * @param drawStroke 是否绘制边框
     * @param drawFill   是否绘制填充
     */
    public void setDrawStyle(boolean drawStroke, boolean drawFill) {
        this.mDrawStroke = drawStroke;
        this.mDrawFill = drawFill;
        invalidate();
    }

    /**
     * 获取边框线宽
     *
     * @return 边框线宽，单位：px
     */
    public int getStrokeLineWidth() {
        return mStrokeLineWidth;
    }

    /**
     * 设置边框线宽
     *
     * @param strokeLineWidth 边框线宽，单位：px
     */
    public void setStrokeLineWidth(int strokeLineWidth) {
        this.mStrokeLineWidth = strokeLineWidth;
        init();
        invalidate();
    }

    /**
     * 获取选中时的边框颜色
     *
     * @return 选中时的边框颜色
     */
    public int getCheckedStrokeColor() {
        return mCheckedStrokeColor;
    }

    /**
     * 设置选中时的边框颜色
     *
     * @param checkedStrokeColor 选中时的边框颜色
     */
    public void setCheckedStrokeColor(int checkedStrokeColor) {
        this.mCheckedStrokeColor = checkedStrokeColor;
        invalidate();
    }

    /**
     * 获取未选中时的边框颜色
     *
     * @return 未选中时的边框颜色
     */
    public int getNoCheckedStrokeColor() {
        return mNoCheckedStrokeColor;
    }

    /**
     * 设置未选中时的边框颜色
     *
     * @param noCheckedStrokeColor 未选中时的边框颜色
     */
    public void setNoCheckedStrokeColor(int noCheckedStrokeColor) {
        this.mNoCheckedStrokeColor = noCheckedStrokeColor;
        invalidate();
    }

    /**
     * 获取选中时的填充色
     *
     * @return 选中时的填充色
     */
    public int getCheckedFillColor() {
        return mCheckedFillColor;
    }

    /**
     * 设置选中时的填充色
     *
     * @param checkedFillColor 选中时的填充色
     */
    public void setCheckedFillColor(int checkedFillColor) {
        this.mCheckedFillColor = checkedFillColor;
        invalidate();
    }

    /**
     * 获取未选中时的填充色
     *
     * @return 未选中时的填充色
     */
    public int getNoCheckedFillColor() {
        return mNoCheckedFillColor;
    }

    /**
     * 设置未选中时的填充色
     *
     * @param noCheckedFillColor 未选中时的填充色
     */
    public void setNoCheckedFillColor(int noCheckedFillColor) {
        this.mNoCheckedFillColor = noCheckedFillColor;
        invalidate();
    }

    /**
     * 获取选中时的文字颜色
     *
     * @return 选中时的文字颜色
     */
    public int getCheckedTextColor() {
        return mCheckedTextColor;
    }

    /**
     * 设置选中时的文字颜色
     *
     * @param checkedTextColor 选中时的文字颜色
     */
    public void setCheckedTextColor(int checkedTextColor) {
        this.mCheckedTextColor = checkedTextColor;
        invalidate();
    }

    /**
     * 获取未选中时的文字颜色
     *
     * @return 未选中时的文字颜色
     */
    public int getNoCheckedTextColor() {
        return mNoCheckedTextColor;
    }

    /**
     * 设置未选中时的文字颜色
     *
     * @param noCheckedTextColor 未选中时的文字颜色
     */
    public void setNoCheckedTextColor(int noCheckedTextColor) {
        this.mNoCheckedTextColor = noCheckedTextColor;
        invalidate();
    }

    /**
     * dp转px
     *
     * @param context 环境
     * @param dpValue dp
     * @return px
     */
    public static int dp2px(Context context, float dpValue) {
        return (int) (dpValue * context.getResources().getDisplayMetrics().density + 0.5f);
    }
}
